<?php


namespace app\home\controller;

use think\Db;
use app\common\library\Tree;
use think\Validate;
use app\common\library\Yunpian;
use think\captcha\Captcha;
use app\common\library\Hash;
use think\facade\Session;
use Endroid\QrCode\ErrorCorrectionLevel;
use Endroid\QrCode\LabelAlignment;
use Endroid\QrCode\QrCode;
use think\facade\Log;

class Wxpay extends Base
{
    const SSLCERT_PATH = '/Data/WeiXinPay/apiclient_cert.pem';
    const SSLKEY_PATH = '/Data/WeiXinPay/apiclient_key.pem';
    const REPORT_LEVENL = 1;

    //微信通知
    public function notify()
    {
        Log::write('微信返回信息', 'WXNOTIFY');
        //获取通知的数据
        $xml = file_get_contents('php://input');
        $redata = $this->FromXml($xml);
        $this->wechat_pay_db($redata);
    }


    //订单查询
    public function orderquery()
    {
        Log::write('微信支付查询', 'WXNOTIFY');

        $attach['uid'] = session('uid');
        $attach['product_info_id'] = input('get.product_info_id');
        $params['appid'] = config('param.appid');
        $params['mch_id'] = config('param.mch_id');
        $params['nonce_str'] = $this->getNonceStr();
        $params['out_trade_no'] = cache('wechat_pay_order_' . $attach['uid'] . '_' . $attach['product_info_id']);
        $params['sign'] = $this->MakeSign($params);
        $redata = $this->wechat_query($this->ToXml($params));
        if ($redata['trade_state'] != 'SUCCESS') {
            $this->error('支付失败');
        }
        if ($this->wechat_pay_db($redata, 1)) {
            $this->success('支付成功');
        } else {
            $this->error('支付失败');
        };

    }


    public function wechat_query($params)
    {
        $url = 'https://api.mch.weixin.qq.com/pay/orderquery';
        $redata = $this->postXmlCurl($params, $url, false);
        // dump($redata);
        $redata = $this->FromXml($redata);
        // dump($redata);
        // exit;
        return $redata; //成功

    }

    public function wechat_pay_db($redata = '', $status = 0)
    {
        //给微信回复
        if ($redata['return_code'] == 'SUCCESS' && $status == 0) {
            $rdata['return_code'] = 'SUCCESS';
            $rdata['return_msg'] = 'OK';
            echo $this->ToXml($rdata);
        }
        // dump($redata);
        if ($redata['return_code'] == 'FAIL') {
            Log::write('微信支付交互失败', 'WXNOTIFY');
            DB::name('product_info')->where('id', $redata['attach'])->update(['status' => 4]);
            return false;
        } else {
            Log::write('微信支付交互' . json_encode($redata), 'WXNOTIFY');
            if (cache('wxpay_id_' . $redata['out_trade_no']) == 1) {
                return true;
            } else {

                Db::startTrans();
                try {
                    cache('wxpay_id_' . $redata['out_trade_no'], 1, 3700);
                    $info = DB::name('product_order')->where('id', $redata['attach'])->find();//取信息
                    if ($info['product_run_id'] == 0) {
                        $data['product_id'] = $info['product_id'];
                        $data['s_time'] = time();
                        $data['e_time'] = time() + $info['day'] * 86400;
                        $data['uid'] = $info['uid'];
                        $id = DB::name('product_run')->insertGetId($data);//新增产品
                        //设置域名
                        $domain = db::name('product')->where('id', $info['product_id'])->value('domain');
                        DB::name('product_run')->where('id', $id)->update(['domain' => $this->domain($domain)]);
                    } else {
                        //已有产品增加天数；
                        $id = $info['product_run_id'];
                        DB::name('product_run')->where('id', $info['product_run_id'])->setInc('e_time', $info['day'] * 86400);
                    }
                    DB::name('product_order')->where('id', $redata['attach'])->update(['status' => 3, 'product_run_id' => $id]);
                    //增加产品总金额
                    DB::name('user')->where('id', $info['uid'])->seInc('sum_price', $info['price']);
                    Db::commit();

                } catch (\Exception $e) {
                    Db::rollback();
                }
                //产品添加
                return true;
            }
        }
    }

    public function domain($domain = '')
    {
        $mCode = array('2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z');
        $subdomain = '';
        foreach (array_rand($mCode, 4) as $key) {
            $subdomain .= $mCode[$key];
        }
        if (DB::name('product_run')->where('domain', $subdomain . $domain)->find()) {
            $this->domain($domain);
        } else {
        }
        return $subdomain . '.' . $domain;
    }

    public function order_status()
    {
        $post = $this->request->param();
        if ($this->request->isPost()) {
            $order = DB::name('product_order')->where('id', $post['order_no'])->find();
            $status_info = config('param.order_status');
            $msg = $order['status'] ? $status_info[$order['status']] : $order['status'];
            $data = DB::name('product_run')->where('id', $order['product_run_id'])->find();
            if ($data) {
                $data = '产品处理完成';
            } else {
                $data = '请联系客服';
            }
            if ($order['status'] == 3) {
                $this->success($msg, '', $data);
            } else {
                $this->error('查询订单，没有支付成功', '', $data);
            }
        }

    }

    //组装参数
    public function qrcode()
    {

        $params['appid'] = config('param.appid');
        $params['mch_id'] = config('param.mch_id');
        $params['notify_url'] = Url('/home/Wxpay/notify', '', '', 'www.weibuyun.com');
        // $params['spbill_create_ip'] = $_SERVER['REMOTE_ADDR'];
        $params['trade_type'] = 'NATIVE';//交易类型
        $params['nonce_str'] = $this->getNonceStr();

        $info = DB::name('product_info')->where('id', input('param.product_info_id'))->find();
        $body = DB::name('product')->where('id', $info['product_id'])->value('title');
        $params['body'] = $body . '|' . $info['title'];
        $params['out_trade_no'] = $this->get_order_id();//订单号
        $params['total_fee'] = $info['price'] * 100;//金额
        //dump($params);
        $params['spbill_create_ip'] = config('param.server_ip');//服务器ip

        $attach['uid'] = session('uid');
        $attach['product_info_id'] = input('param.product_info_id');//产品优惠id
        $attach['product_run_id'] = input('param.product_run_id');
        $attach['c_time'] = time();
        $attach['price'] = $params['total_fee'] / 100;
        $attach['order_id'] = $params['out_trade_no'];
        $attach['status'] = 1;
        $attach['product_id'] = $info['product_id'];
        $attach['day'] = $info['day'];
        $params['attach'] = DB::name('product_order')->insertGetId($attach);//添加订单得订单号
        $params['sign'] = $this->MakeSign($params);
        //dump($params);
        $redata = $this->unifiedorder($this->ToXml($params)); //统一下单api
        if ($redata) {
            cache('wechat_pay_order_' . $attach['uid'] . '_' . $attach['product_info_id'], $params['out_trade_no'], 7200);
            return $this->success($this->phpqrcode($redata['code_url']), '', $params['attach']);//二维码
        } else {
            return FALSE;
        }
    }

    //生成二维码
    public function phpqrcode($url)
    {
        $file_name = 'qrcode';
        $qrCode = new QrCode();
        $qrCode->setText($url);
        $qrCode->setSize(250);
        $qrCode->setForegroundColor(array('r' => 0, 'g' => 0, 'b' => 0, 'a' => 0));
        $qrCode->setBackgroundColor(array('r' => 255, 'g' => 255, 'b' => 255, 'a' => 0));
        $qrCode->setLabelFontSize(16);
        //ob_clean();
        //header('Content-Type: ' . $qrCode->getContentType());


        $file_path = $file_name . '/qrcode' . uniqid() . '.png';
        if (!file_exists($file_name)) {
            mkdir($file_name, 0777, true);
        }
        try {
            $qrCode->writeFile($file_path);
            //echo $file_path;
            return 'https://www.weibuyun.com/' . $file_path;
        } catch (\Exception $e) {
            return false;
        }

    }


    //统计下单
    public function unifiedorder($params)
    {
        $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        $redata = $this->postXmlCurl($params, $url, false);
        // dump($redata);
        $redata = $this->FromXml($redata);
        // dump($redata);
        // exit;
        if ($redata['return_code'] == 'SUCCESS' && $redata['mch_id'] == config('param.mch_id')) {
            return $redata; //成功
        } else {
            return FALSE;
        }
    }

    public function FromXml($xml)
    {
        libxml_disable_entity_loader(true);
        return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
    }

    private static function postXmlCurl($xml, $url, $useCert = false, $second = 30)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_TIMEOUT, $second);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, TRUE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); //严格校验
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        if ($useCert == true) {
            curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
            curl_setopt($ch, CURLOPT_SSLCERT, WxPayConfig::SSLCERT_PATH);
            curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');
            curl_setopt($ch, CURLOPT_SSLKEY, WxPayConfig::SSLKEY_PATH);
        }
        curl_setopt($ch, CURLOPT_POST, TRUE);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
        $data = curl_exec($ch);
        if ($data) {
            curl_close($ch);
            return $data;
        } else {
            $error = curl_errno($ch);
            \Think\Log::write('给微信提交数据返回错误' . $error, 'WARN');
        }
    }

    public function ToXml($xml_array)
    {
        $xml = "<xml>";
        foreach ($xml_array as $key => $val) {
            if (is_numeric($val)) {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            } else {
                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
            }
        }
        $xml .= "</xml>";
        //  dump($xml);
        return $xml;
    }

    /**
     * 生成签名
     * @return 签名，本函数不覆盖sign成员变量，如要设置签名需要调用SetSign方法赋值
     */
    public function MakeSign($xml_array)
    {
        //签名步骤一：按字典序排序参数
        ksort($xml_array);
        //dump($xml_array);
        $string = $this->ToUrlParams($xml_array);
        //签名步骤二：在string后加入C('WX_PAY_KEY')
        $string = $string . "&key=" . config('param.wxpay_key');;
        //签名步骤三：MD5加密
        $string = md5($string);
        //签名步骤四：所有字符转为大写
        $result = strtoupper($string);
        return $result;
    }

    /**
     * 格式化参数格式化成url参数
     */
    public function ToUrlParams($xml_array)
    {
        $buff = "";
        foreach ($xml_array as $k => $v) {
            if ($k != "sign" && $v != "" && !is_array($v)) {
                $buff .= $k . "=" . $v . "&";
            }
        }
        $buff = trim($buff, "&");
        return $buff;
    }

    /**
     * 产生随机字符串，不长于32位
     */
    public static function getNonceStr($length = 32)
    {
        $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
        $str = "";
        for ($i = 0; $i < $length; $i++) {
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }

    public function get_order_id()
    {
        $yCode = array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J');
        $mCode = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V');
        return 'T' . $yCode[intval(date('Y')) - 2020] . strtoupper(dechex(date('m'))) . $mCode[intval(date('d') - 0)] . substr(time(), -5) . substr(microtime(), 2, 5) . sprintf('%02d', rand(0, 99));
    }


}